#include "z80.h"

#define GB_Z80
#define DEBUG

REGS r;
STATUS s;

void print_regs();

void prepare_vm(void)
{
	r.rr = (UINT8**)malloc(4*8);
	r.rrr = (UINT16**)malloc(4*4);
	
	r.BC.B.B = 0;
	r.BC.B.C = 0;
	r.DE.B.D = 0;
	r.DE.B.E = 0;
	r.HL.B.H = 0;
	r.HL.B.L = 0;
	r.AF.B.A = 0;
	
	r.PC = 0;
	
	r.rr[0] = &r.BC.B.B;
	r.rr[1] = &r.BC.B.C;
	r.rr[2] = &r.DE.B.D;
	r.rr[3] = &r.DE.B.E;
	r.rr[4] = &r.HL.B.H;
	r.rr[5] = &r.HL.B.L;
	
	r.rr[7] = &r.AF.B.A;
	
	r.rrr[0] = &r.BC.BC;
	r.rrr[1] = &r.DE.DE;
	r.rrr[2] = &r.HL.HL;
	r.rrr[3] = &r.SP;
	
	//print_regs();
}

void print_regs(void)
{
	printf("A: %.2X,  F: %.2X,  B: %.2X,  C: %.2X,  D: %.2X,  E: %.2X,  H: %.2X,  L: %.2X - HL: %.4X, PC: %.4X\r\n", r.AF.B.A, r.AF.B.F, r.BC.B.B, r.BC.B.C, r.DE.B.D, r.DE.B.E, r.HL.B.H, r.HL.B.L, r.HL.HL, r.PC);
	
	printf("RAM: ");
	for (int i = 0; i < 10; ++i)
		printf("%u: %u, ", i, mem_read(0x8000 + i));
	printf("\r\n");
}

/*	LD r, (HL)
	LD (HL), r
	LD r, r'
	LD (HL), n
	LD r, n
*/

/* carry flag */
inline void setC(bool value)
{
	
}

/* add/subtract flag */
inline void setN(bool value)
{
	
}

/* parity/overflow flag */
inline void setPV(bool value)
{
	
}

/* half carry flag */
inline void setH(bool value)
{
	
}

/* zero flag */
inline void setZ(bool value)
{
	
}

/* sign flag */
inline void setS(bool value)
{
	
}

UINT8 execute_instruction(UINT8 opcode)
{	
	/*#ifdef DEBUG
		printf("Executing: %s\r\n", mnemonics[opcode]);
	#endif*/
	
	/* LD A, (BC) */
	if (opcode == 0x0A)
	{
		r.AF.B.A = mem_read(r.BC.BC);
	}
	/* LD A, (DE) */
	else if (opcode == 0x1A)
	{
		r.AF.B.A = mem_read(r.DE.DE);
	}
	/* LD A, (nn) - LDD A, (HL) */
	else if (opcode == 0x3A)
	{		
		#ifndef GB_Z80
		
			UINT16 address = mem_read(r.PC) | ((mem_read(r.PC+1) << 8) & 0xFF00);

			r.AF.B.A = mem_read(address);
		
			r.PC += 2;		
		#else
		
			r.AF.B.A = mem_read(r.HL.HL);
			--r.HL.HL;
		
		#endif
	}
	/* LD (BC), A */
	else if (opcode == 0x02)
	{
		mem_write(r.BC.BC, r.AF.B.A);
	}
	/* LD (DE), A */
	else if (opcode == 0x12)
	{
		mem_write(r.DE.DE, r.AF.B.A);
	}
	/* LD (nn), A - LDD (HL), A */
	else if (opcode == 0x32)
	{
		#ifndef GB_Z80
				
			UINT16 address = mem_read(r.PC) | ((mem_read(r.PC+1) << 8) & 0xFF00);
				
			mem_write(address, r.AF.B.A);
				
			r.PC += 2;
				
		#else
				
			mem_write(r.HL.HL, r.AF.B.A);
			--r.HL.HL;
				
		#endif		
	}
	/* LD HL, (nn) - LDI A, (HL) */
	else if (opcode == 0x2A)
	{
		#ifndef GB_Z80
			
			r.HL.B.L = mem_read(r.PC);
			++r.PC;
			
			r.HL.B.H = mem_read(r.PC)
			++r.PC;
		
		#else
		
			r.AF.B.A = mem_read(r.PC) | ((mem_read(r.PC+1) << 8) & 0xFF00);
			++r.HL.HL;
		
		#endif
	}
	/* LD dd, nn */
	else if ((opcode & 0xCF) == 0x01)
	{
		*r.rrr[(opcode & 0x30) >> 4] = mem_read(r.PC) | ((mem_read(r.PC+1) << 8) & 0xFF00);
		
		r.PC += 2;
	}
	/* LD r, (HL) */
	else if ((opcode & 0xC7) == 0x46)
	{
		*r.rr[(opcode & 0x38) >> 3] = mem_read(r.HL.HL);
	}
	/* LD (HL), r */
	else if ((opcode & 0xF8) == 0x70)
	{
		mem_write(r.HL.HL, *r.rr[opcode & 0x07]);
	}
	/* LD r, r' (copia da registro a registro) */	
	else if ((opcode & 0xC0) == 0x40)
	{
		*r.rr[(opcode & 0x38) >> 3] = *r.rr[opcode & 0x07];
	}
	/* LD (HL), n */
	else if (opcode == 0x36)
	{
		mem_write(r.HL.HL, mem_read(r.PC));
		++r.PC;
	}
	/* LD r, n (copia da 0-255 a registro) */	
	else if ((opcode & 0xC7) == 0x06)
	{
		*r.rr[(opcode & 0x38) >> 3] = mem_read(r.PC);
		++r.PC;
	}
	/* COMANDI 0xCB */
	else if (opcode == 0xCB)
	{
		UINT8 opcode2 = mem_read(r.PC);
		++r.PC;
		
		/* RLC r */
		if ((opcode2 & 0xF8) == 0x00)
		{
			/* TODO IMPLEMENTARE */
		}
	}
	/* NOP */
	else if (opcode == 0x00)
	{
		/* fai un cazzio */
	}
	
	return opcode;
	
	//print_regs();
	
}

UINT8 fetch_instruction(void)
{
	/* legge un byte per capire l'opcode */
	UINT8 opcode = mem_read(r.PC);
	
	/* chiaramente incrementa PC (e va fatto ogni volta che vengono letti successivi byte
	   per istruzioni più lunge di 1)
	*/
	++r.PC;
	
	return execute_instruction(opcode);	
}





